home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1998…tember: Reference Library / Dev.CD Sep 98 RL2.toast / What's New / Software Development Kits / MacOS USB DDK / Examples / PrinterClassDriver / PrinterClassDriver.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-07-20  |  70.8 KB  |  2,273 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        PrinterClassDriver.c
  3.  
  4.     Contains:    MacOS USB printer class driver
  5.                 [ref. IEEE Std 1284-1994]
  6.  
  7.     Version:    xxx put version here xxx
  8.  
  9.     Copyright:    1998 by Apple Computer, Inc., all rights reserved.
  10.  
  11.  
  12. */
  13.  
  14.  
  15. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  16.     includes
  17.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  18. #include <Devices.h>
  19. #include <DriverServices.h>
  20. #include <Interrupts.h>
  21. #include <LowMem.h>
  22. #include <Folders.h>
  23. #include <String.h>
  24. #include <stdio.h>
  25. #include <USB.h>
  26.  
  27. #ifndef __CODEFRAGMENTS__
  28. #include <codefragments.h>
  29. #endif
  30.  
  31. #include "PrinterClassDriver.h"
  32. #include "TradDriverLoaderLib.h"
  33.  
  34. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  35.     constants
  36.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  37. #define MAX_SUFFIX                    127        // maximum copies we'll enter in unit table
  38. #define kUSBParallelDrvrRsrcID    12
  39. #define kMinDrvrUnitNumber            48            // minimum unit table entry which we'll install
  40. #define kUSS720MillisecondDelay    3*1000    // poll every three seconds
  41.  
  42. #define kUSBAttributeBulk            0x02
  43. #define kUSBInputEndpointMask        0x80
  44.  
  45. enum
  46. {
  47.     kCString = 0,                // StateStr, USBStatusStr selector
  48.     kPString,                    // StateStr, USBStatusStr selector
  49.     kDrvrFirstDigit = 5        // length_byte + ".USB" = 5
  50. };
  51.  
  52. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  53.     globals
  54.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  55. struct usbPrinterPBStruct    printerClassRecord;
  56. FSSpec                            printerClassDriverFileSpec;
  57. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  58.     prototypes
  59.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  60.  
  61. static void    PrinterDeviceCompletionProc(USBPB *pb);
  62. static void SetNullUSBParamBlock( USBDeviceRef dev, USBPB *pb );
  63. static        USBEndPointDescriptor *FindEndpoint( USBInterfaceDescriptor *pInterface, int endpointType );
  64. static void     SoftReset( USBPB *usbprint, short interfaceNum );
  65. static void     CapabilityRequest( USBPB *pb, Ptr p, long length, short config, short interfaceNum, short alternateSetting );
  66. static void     CentronicsStatus( USBPB *usbprint, Ptr p, short interfaceNum );
  67.  
  68. void            PrinterDeviceInitiateTransaction(USBPB *pb);
  69.  
  70. OSErr            CFMInitialization( CFragInitBlock *initBlock );
  71.  
  72. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  73.     Name:        HexStr
  74.  
  75.     Input Parameters:    
  76.         v                unsigned long value
  77.         
  78.     Output Parameters:
  79.         p                8 bytes: hex string representing value
  80.         
  81.     Description:
  82.  
  83.     Change History:
  84.         28 Feb 1998,    oja:        Original version.
  85. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  86. static void
  87. HexStr( unsigned long v, unsigned char *p )
  88. {
  89.     int    shift;
  90.     
  91.     for ( shift = 32-4; shift >= 0; shift -= 4 )
  92.     {
  93.         char c = (v >> shift) & 0x0F;
  94.         *p++ = c + (c > 9? ('A'-10): '0');
  95.     }
  96. }
  97.  
  98. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  99.     Name:        USBStatusStr
  100.  
  101.     Input Parameters:    
  102.         usbStatus            usb error code
  103.         kind                    kPString or kCString
  104.         
  105.     Output Parameters:
  106.         unsigned char *    description of error (c-string or p-string)
  107.  
  108.     Description:
  109.         a simple mapping of errors to human-readable form
  110.  
  111.     Change History:
  112.         24 Apr 1998,    oja:        param to HexStr was off-by-one
  113.         26 Mar 1998,    oja:        added kStrPrintClass to catenated strings
  114.         28 Feb 1998,    oja:        Original version.
  115. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  116. static unsigned char *
  117. USBStatusStr( OSStatus usbStatus, int kind )
  118. {
  119.     unsigned char *p;
  120.  
  121.     switch ( usbStatus )
  122.     {
  123.         case    kUSBInternalErr:                    p = "\p" kStrPrinterClass "Internal error"; break;
  124.         case    kUSBUnknownDeviceErr:            p = "\p" kStrPrinterClass "Unknown device"; break;
  125.         case    kUSBUnknownPipeErr:                 p = "\p" kStrPrinterClass "Unknown pipe"; break;
  126.         case    kUSBTooManyPipesErr:                p = "\p" kStrPrinterClass "Too many pipes"; break;
  127.         case    kUSBIncorrectTypeErr:            p = "\p" kStrPrinterClass "Incorrect type"; break;
  128.         case    kUSBRqErr:                            p = "\p" kStrPrinterClass "Request error"; break;
  129.         case    kUSBUnknownRequestErr:            p = "\p" kStrPrinterClass "Unknown request"; break;
  130.         case    kUSBTooManyTransactionsErr:    p = "\p" kStrPrinterClass "Too many transactions"; break;
  131.         case    kUSBAlreadyOpenErr:                p = "\p" kStrPrinterClass "Already open"; break;
  132.         case    kUSBNoDeviceErr:                    p = "\p" kStrPrinterClass "No device"; break;
  133.         case    kUSBDeviceErr:                        p = "\p" kStrPrinterClass "Device error"; break;
  134.         case    kUSBOutOfMemoryErr:                p = "\p" kStrPrinterClass "Out of memory"; break;
  135.         case    kUSBNotFound:                        p = "\p" kStrPrinterClass "Not found"; break;
  136.         case    kUSBLinkErr:                        p = "\p" kStrPrinterClass "Link Err"; break;
  137.         case    kUSBCRCErr:                            p = "\p" kStrPrinterClass "Comms/Device err, bad CRC";  break;        
  138.         case    kUSBBitstufErr:                    p = "\p" kStrPrinterClass "Comms/Device err, bitstuffing"; break;        
  139.         case    kUSBDataToggleErr:                p = "\p" kStrPrinterClass "Comms/Device err, Bad data toggle"; break;        
  140.         case    kUSBEndpointStallErr:            p = "\p" kStrPrinterClass "Device didn't understand"; break;        
  141.         case    kUSBNotRespondingErr:            p = "\p" kStrPrinterClass "No device, device hung"; break;        
  142.         case    kUSBPIDCheckErr:                    p = "\p" kStrPrinterClass "Comms/Device err, PID CRC error"; break;        
  143.         case    kUSBWrongPIDErr:                    p = "\p" kStrPrinterClass "Comms/Device err, Bad or wrong PID"; break;        
  144.         case    kUSBOverRunErr:                    p = "\p" kStrPrinterClass "Packet too large or more data than buffer"; break;        
  145.         case    kUSBUnderRunErr:                    p = "\p" kStrPrinterClass "Less data than buffer"; break;        
  146.         case    kUSBRes1Err:                        p = "\p" kStrPrinterClass "kUSBRes1Err"; break;        
  147.         case    kUSBRes2Err:                        p = "\p" kStrPrinterClass "kUSBRes1Err"; break;        
  148.         case    kUSBBufOvrRunErr:                    p = "\p" kStrPrinterClass "Buffer over run error"; break;        
  149.         case    kUSBBufUnderRunErr:                p = "\p" kStrPrinterClass "Buffer under run error"; break;        
  150.         case    kUSBNotSent1Err:                    p = "\p" kStrPrinterClass "Transaction not sent1"; break;        
  151.         case    kUSBNotSent2Err:                    p = "\p" kStrPrinterClass "Transaction not sent2"; break;    
  152.         default:
  153.             p = "\p" kStrPrinterClass "Unknown error nnnnnnnn";
  154.             HexStr( usbStatus, p + *p - 8 + 1 );
  155.             break;
  156.     }
  157.     
  158.     return kind == kPString? p: p + 1;
  159. }
  160.  
  161. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  162.     Name:        StateStr
  163.  
  164.     Input Parameters:    
  165.         usbRefCon            usb error code
  166.         kind                    kPString or kCString
  167.         
  168.     Output Parameters:
  169.         unsigned char *    description of state (c-string or p-string)
  170.  
  171.     Description:
  172.         a simple mapping of states to human-readable form
  173.  
  174.     Change History:
  175.         24 Apr 1998,    oja:        param to HexStr was off-by-one
  176.         26 Mar 1998,    oja:        added kStrPrintClass to catenated strings
  177.         28 Feb 1998,    oja:        Original version.
  178. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  179. static unsigned char *
  180. StateStr( OSStatus refCon, int kind )
  181. {
  182.     unsigned char *p;
  183.  
  184.     refCon &= ~(kTransactionPending | kRetryTransaction | kAsyncTransaction | kReturnFromDriver);
  185.     switch ( refCon )
  186.     {
  187.         case kGetConfigurationDescriptor:        p = "\p" kStrPrinterClass "kGetConfigurationDescriptor"; break;
  188.         case kGetFullConfiguration:                p = "\p" kStrPrinterClass "kGetFullConfiguration"; break;
  189.         case kSetInterface:                            p = "\p" kStrPrinterClass "kSetInterface"; break;
  190.         case kGetCapabilityString:                    p = "\p" kStrPrinterClass "kGetCapabilityString"; break;
  191.         case kDelayGetCapability:                    p = "\p" kStrPrinterClass "kDelayGetCapability"; break;
  192.         case kGetFullCapabilityString:            p = "\p" kStrPrinterClass "kGetFullCapabilityString"; break;
  193.         case kGetInterface:                            p = "\p" kStrPrinterClass "kGetInterface"; break;
  194.         case kOpenBulkOutPipe:                        p = "\p" kStrPrinterClass "kOpenBulkOutPipe"; break;
  195.         case kOpenBulkInPipe:                        p = "\p" kStrPrinterClass "kOpenBulkInPipe"; break;
  196.         case kEnterNameRegistry:                    p = "\p" kStrPrinterClass "kEnterNameRegistry"; break;
  197.         default:
  198.             p = "\p" kStrPrinterClass "Unknown state nnnnnnnn";
  199.             HexStr( refCon, p + *p - 8 + 1 );
  200.             break;
  201.     }
  202.     return kind == kPString? p: p + 1;    
  203. }
  204.  
  205. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  206.     Name:        HiHex
  207.  
  208.     Input Parameters:    
  209.         v                        only low byte used
  210.         
  211.     Output Parameters:
  212.         <function result>    high nibble represented as ASCII char
  213.         
  214.     Description:
  215.  
  216.     Change History:
  217.         20 Mar 1998,    oja:        Original version.
  218. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  219. static unsigned char
  220. HiHex( int v )
  221. {
  222.     unsigned char    hinibble = (v >> 4) & 0x0f;
  223.     return hinibble + ((hinibble > 9)? ('A'-10): '0');
  224. }
  225.  
  226. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  227.     Name:        LoHex
  228.  
  229.     Input Parameters:    
  230.         v                        only low byte used
  231.         
  232.     Output Parameters:
  233.         <function result>    low nibble represented as ASCII char
  234.         
  235.     Description:
  236.  
  237.     Change History:
  238.         20 Mar 1998,    oja:        Original version.
  239. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  240. static unsigned char
  241. LoHex( int v )
  242. {
  243.     unsigned char    lonibble = v & 0x0f;
  244.     return lonibble + ((lonibble > 9)? ('A'-10): '0');
  245. }
  246.  
  247. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  248.     Name:        immediateError
  249.  
  250.     Input Parameters:    
  251.         
  252.     Output Parameters:
  253.         
  254.     Description:
  255.  
  256.     Change History:
  257.         28 Feb 1998,    oja:        Original version.
  258. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  259. static Boolean
  260. immediateError(OSStatus err)
  261. {
  262.     return((err != kUSBPending) && (err != noErr) );
  263. }
  264.  
  265. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  266.     Name:        SetNullUSBParamBlock
  267.  
  268.     Input Parameters:    
  269.         pb                    pointer to USB parameter block
  270.         dev                USB device reference
  271.     Output Parameters:
  272.         pb                    all fields set to default values
  273.  
  274.     Description:
  275.         setup a USB parameter block for use by the current device
  276.  
  277.     Change History:
  278.          8 Jun 1998,    oja:        modified for new param blocks
  279.         28 Feb 1998,    oja:        Original version.
  280. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  281. static void
  282. SetNullUSBParamBlock( USBDeviceRef dev, USBPB *pb )
  283. {
  284.     pb->qlink = NULL;
  285.     pb->qType = 0;
  286.     pb->pbLength = sizeof(USBPB);
  287.     pb->pbVersion = kUSBCurrentPBVersion;
  288.     pb->usbFlags = 0;
  289.  
  290.     pb->usbReference = dev;
  291. }
  292.  
  293.  
  294. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  295.     Name:        CountInterface
  296.  
  297.     Input Parameters:    
  298.         pConfigDesc            pointer to USB device configuration string
  299.         intClass                USB class id
  300.         intSubClass            USB subclass id
  301.     
  302.     Output Parameters:
  303.         <function result>    number of interfaces which match the criteria
  304.     
  305.     Description:
  306.         Count the number of interfaces (and alternates) which match the
  307.         desired class and subclass.
  308.  
  309.     Change History:
  310.         26 Mar 1998,    oja:        use USBToHostWord to access length of
  311.                                         Configuration Descriptor
  312.         28 Feb 1998,    oja:        Original version.
  313. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  314. static int
  315. CountInterface(
  316.     USBConfigurationDescriptorPtr pConfigDesc,
  317.     int intClass,
  318.     int intSubClass
  319. )
  320. {
  321.     //
  322.     //    find an interface (and alternateSetting) which allows the desired class, subclass and protocol
  323.     //
  324.     int                                numInterfaces;
  325.     UInt32                            totalLength;
  326.     void                                *pEndOfDescriptors;
  327.     USBInterfaceDescriptorPtr    pMyIntDesc;
  328.     USBDescriptorHeaderPtr        pCurrentDesc;
  329.     Ptr                                p;
  330.     
  331.     totalLength = USBToHostWord( ((USBConfigurationDescriptorPtr)pConfigDesc)->totalLength );
  332.     pEndOfDescriptors = (Ptr)pConfigDesc + totalLength;                // get the total length and add it to the start of the config space
  333.     pCurrentDesc = (USBDescriptorHeaderPtr)pConfigDesc;                // point the currentdesc to the start of the config space
  334.     
  335.     numInterfaces = 0;
  336.     while (pCurrentDesc < pEndOfDescriptors)                        // as long as we haven't exhausted all the descriptors
  337.     {
  338.         if (pCurrentDesc->descriptorType == kUSBInterfaceDesc)    // look at the current descriptor
  339.         {
  340.             pMyIntDesc = (USBInterfaceDescriptorPtr)pCurrentDesc;    // if it's an interface descriptor
  341.             if (pMyIntDesc->interfaceClass == intClass &&
  342.                     pMyIntDesc->interfaceSubClass == intSubClass )        // see if it's the request descriptor
  343.             {
  344.                 ++numInterfaces;
  345.             }
  346.         }
  347.         if ( pCurrentDesc->length == 0 )
  348.         {
  349.             IF_DEBUG( DebugStr( "\pCountInterfaces NULL" ) );
  350.             break;
  351.         }
  352.         p = (Ptr)pCurrentDesc + pCurrentDesc->length;
  353.         pCurrentDesc = (USBDescriptorHeaderPtr) p;                    // Nope, that either wasn't an interface descriptor
  354.     }                                                            // or it was, but not the droid we're looking for.
  355.     return numInterfaces;
  356. }
  357.  
  358.  
  359. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  360.     Name:        FindInterface
  361.  
  362.     Input Parameters:
  363.         pPrinterPB
  364.         protocol                                (USB specification) protocol constant
  365.         
  366.     Output Parameters:
  367.         pPrinterPB->pb.usbBuffer        pointer to the interface
  368.         pPrinterPB->pb.usbReqCount        offset to the interface
  369.  
  370.     Description:
  371.         Synchronous.
  372.  
  373.         find a print interface (and alternateSetting) which allows 
  374.         the desired protocol
  375.         
  376.         Note although USBFindNextInterfaceDescriptor returns immediately
  377.         it still requires a completion routine.
  378.  
  379.     Change History:
  380.         28 Feb 1998,    oja:        Original version.
  381. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  382. static struct USBInterfaceDescriptor *
  383. FindInterface( USBConfigurationDescriptorPtr pConfigDesc, int protocol )
  384. {
  385.     //
  386.     //    find a print interface (and alternateSetting) which allows 
  387.     //        the desired protocol
  388.     //
  389.     //
  390.     int                                numInterfaces;
  391.     UInt32                            totalLength;
  392.     void                                *pEndOfDescriptors;
  393.     USBInterfaceDescriptorPtr    pMyIntDesc;
  394.     USBDescriptorHeaderPtr        pCurrentDesc;
  395.     Ptr                                p;
  396.     
  397.     totalLength = USBToHostWord( pConfigDesc->totalLength );
  398.     pEndOfDescriptors = (Ptr)pConfigDesc + totalLength;                // get the total length and add it to the start of the config space
  399.     pCurrentDesc = (USBDescriptorHeaderPtr)pConfigDesc;                // point the currentdesc to the start of the config space
  400.     
  401.     numInterfaces = 0;
  402.     while (pCurrentDesc < pEndOfDescriptors)                        // as long as we haven't exhausted all the descriptors
  403.     {
  404.         if (pCurrentDesc->descriptorType == kUSBInterfaceDesc)    // look at the current descriptor
  405.         {
  406.             pMyIntDesc = (USBInterfaceDescriptorPtr)pCurrentDesc;    // if it's an interface descriptor
  407.             if (pMyIntDesc->interfaceClass == kUSBPrintClass &&
  408.                     pMyIntDesc->interfaceSubClass == kUSBPrintSubClass &&
  409.                     pMyIntDesc->interfaceProtocol == protocol    )        // see if it's the requested descriptor
  410.                 break;
  411.         }
  412.         if ( pCurrentDesc->length == 0 )
  413.         {
  414.             IF_DEBUG( DebugStr( "\pFindInterface NULL" ) );
  415.             pCurrentDesc = pEndOfDescriptors;    // shouldn't happen
  416.             break;
  417.         }
  418.         p = (Ptr)pCurrentDesc + pCurrentDesc->length;                    // Nope, that either wasn't an interface descriptor
  419.         pCurrentDesc = (USBDescriptorHeaderPtr) p;
  420.     }                                                            // or it was, but not the droid we're looking for.
  421.     return pCurrentDesc < pEndOfDescriptors? (struct USBInterfaceDescriptor *) pCurrentDesc: NULL;
  422.  
  423. }
  424.  
  425. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  426.     Name:        FindEndpoint
  427.  
  428.     Input Parameters:    
  429.         pInterface            pointer to interface descriptor
  430.         kind                    kUSBIn, kUSBOut
  431.         
  432.     Output Parameters:
  433.         result                pointer to bulk endpoint descriptor
  434.     
  435.     Description:
  436.  
  437.     Change History:
  438.          8 Jun 1998,    oja:        Original version.
  439. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  440.  
  441. static USBEndPointDescriptor *
  442. FindEndpoint( USBInterfaceDescriptor *pInterface, int kind )
  443. {
  444.     USBEndPointDescriptor    *pEndpoint = (USBEndPointDescriptor *) (pInterface->length + (Ptr) pInterface),
  445.                                     *pEndOfEndpoints = pEndpoint + pInterface->numEndpoints;
  446.  
  447.     UInt8                            addressMask = kind == kUSBIn? 0x80: 0;
  448.     while ( pEndpoint < pEndOfEndpoints )
  449.     {
  450.         Ptr    p = (Ptr) pEndpoint;
  451.         if ( pEndpoint->attributes == 2 && ((pEndpoint->endpointAddress & addressMask) == addressMask) )
  452.             break;
  453.         
  454.         p += pEndpoint->length;
  455.         pEndpoint = (USBEndPointDescriptor *) p;
  456.     }
  457.     
  458.     return pEndpoint < pEndOfEndpoints? pEndpoint: NULL;
  459. }
  460.  
  461. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  462.     Name:        ParseCapability
  463.  
  464.     Input Parameters:    
  465.         capability            pointer to 1284-1994 capability string
  466.         attribute            pointer to c-string key we're retrieving (terminate with colon)
  467.         *result_length        maximum length of the result 
  468.         
  469.     Output Parameters:
  470.         result                c-string which followed the key and was terminated by semi-colon
  471.                                 (semi-colon has been stripped)
  472.         *result_length        actual length of the result (may be zero)
  473.     
  474.     Description:
  475.         Search for "attribute" in the 1284 "capability" string
  476.         The identifier is terminated with a semi-colon
  477.  
  478.         Return the attribute in result
  479.             null-string if attribute not found.
  480.  
  481.     Change History:
  482.         28 Feb 1998,    oja:        Original version.
  483. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  484. static void
  485. ParseCapability(
  486.     unsigned char    *capability,
  487.     unsigned char    *attribute,
  488.     unsigned char    *result,
  489.     int                *result_length 
  490. )
  491. {
  492.     //
  493.     //    search for "attribute" in the 1284 "capability" string
  494.     //
  495.     //    the identifier is terminated with a semi-colon
  496.     //
  497.     //    return the attribute in result
  498.     //            null-string if attribute not found
  499.     //
  500.     //    <to do> skip blanks, isolate colon, skip blanks
  501.     //
  502.     int                source_length,
  503.                         target_length;
  504.     unsigned char    *source,
  505.                         *target,
  506.                         *destination;
  507.     //
  508.     //    begin a brute force search
  509.     //
  510.     source = attribute;
  511.     source_length = strlen((char *)attribute );
  512.  
  513.     target = capability + 3;    // skip the length
  514.     target_length =  capability[1] | (capability[0] << 8);
  515.     while ( target_length >= source_length )
  516.     {
  517.         if ( memcmp( source, target, source_length ) == 0 )
  518.             break;
  519.         --target_length;
  520.         ++target;
  521.     }
  522.  
  523.     destination = result;
  524.     *destination = 0;    // empty result
  525.  
  526.     target += source_length;
  527.     target_length -= source_length;    // skip the attribute string
  528.  
  529.     if ( target_length > 0 )
  530.     {
  531.         //
  532.         //    we found the attribute in the capability string
  533.         //
  534.         while ( destination - result < *result_length )    // arbitrarily limit reply
  535.         {
  536.             if ( *target == ';' )
  537.                 break;
  538.             *destination++ = *target++;        // copy a byte of attribute over
  539.         }
  540.         *destination++ = '\0';                        // trailing NUL
  541.         *result_length = destination - result;    // report the length of the data (with trailing NUL)
  542.     }
  543. }
  544.  
  545.  
  546. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  547.     Name:        GetClass
  548.  
  549.     Input Parameters:    
  550.         capability            pointer to 1284-1994 capability string
  551.         *result_length        maximum length of the result 
  552.         
  553.     Output Parameters:
  554.         result                c-string extracted from the MODEL key
  555.         *result_length        actual length of the result  (may be zero)
  556.         
  557.     Description:
  558.         CLASS is a Microsoft extension to the 1284-capability string
  559.         if we don't find it
  560.             we assume that the device is a printer
  561.         Since the USB hardware has already indicated this, we're really allowing
  562.         devices which aren't printers to be reached via the DRVRs we've installed.
  563.  
  564.     Change History:
  565.         26 Mar 1998,    oja:        result_length is output too
  566.         28 Feb 1998,    oja:        Original version.
  567. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  568. static void
  569. GetClass(
  570.     unsigned char    *capability,
  571.     unsigned char    *result,
  572.     int                *result_length
  573. )
  574. {
  575.     //
  576.     //    We supply the upper-case PRINTER to be consistent with 1284-1994
  577.     //        if we don't find a class.
  578.     //
  579.     ParseCapability( capability, (unsigned char *) "CLASS:", result, result_length);
  580.     if ( *result == '\0' )
  581.         ParseCapability( capability, (unsigned char *) "CLS:", result, result_length);
  582.     if ( *result == '\0' )
  583.         strcpy( (char *)result, "PRINTER" );
  584. }
  585.  
  586.  
  587. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  588.     Name:        GetModel
  589.  
  590.     Input Parameters:    
  591.         capability            pointer to 1284-1994 capability string
  592.         *result_length        maximum length of the result 
  593.         
  594.     Output Parameters:
  595.         result                c-string extracted from the MODEL key
  596.         *result_length        actual length of the result  (may be zero)
  597.             
  598.     Description:
  599.         MODEL is a required field of the 1284-capability string
  600.         MODEL may be abbreviated MDL
  601.  
  602.     Change History:
  603.         26 Mar 1998,    oja:        result_length is output too
  604.         28 Feb 1998,    oja:        Original version.
  605. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  606. static void
  607. GetModel(
  608.     unsigned char    *capability, 
  609.     unsigned char    *result,
  610.     int                *result_length
  611. )
  612. {
  613.     //
  614.     //    Most manufacturers abbreviate, so we search for MDL first
  615.     //
  616.     ParseCapability( capability, (unsigned char *) "MDL:", result, result_length );
  617.     if ( *result == '\0' )
  618.         ParseCapability( capability, (unsigned char *) "MODEL:", result, result_length );
  619. }
  620.  
  621.  
  622. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  623.     Name:        GetCommandSet
  624.  
  625.     Input Parameters:    
  626.         
  627.     Output Parameters:
  628.         
  629.     Description:
  630.  
  631.     Change History:
  632.         28 Feb 1998,    oja:        Original version.
  633. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  634. static void
  635. GetCommandSet(
  636.     unsigned char *capability, 
  637.     unsigned char *result,
  638.     int *result_length
  639. )
  640. {
  641.     //
  642.     //    COMMAND-SET is a required field of the 1284-capability string
  643.     //    COMMAND-SET may be abbreviated CMD
  644.     //
  645.     ParseCapability( capability, (unsigned char *) "CMD:", result, result_length );
  646.     if ( *result == '\0' )
  647.         ParseCapability( capability, (unsigned char *) "COMMAND-SET:", result, result_length );
  648. }
  649.  
  650. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  651.     Name:        GetManufacturer
  652.  
  653.     Input Parameters:    
  654.         
  655.     Output Parameters:
  656.         
  657.     Description:
  658.  
  659.     Change History:
  660.         26 Jun 1998,    oja:        Original version.
  661. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  662. static void
  663. GetManufacturer(
  664.     unsigned char *capability, 
  665.     unsigned char *result,
  666.     int *result_length
  667. )
  668. {
  669.     //
  670.     //    MANUFACTURER is a required field of the 1284-capability string
  671.     //    MANUFACTURER may be abbreviated MFG
  672.     //
  673.     ParseCapability( capability, (unsigned char *) "MFG:", result, result_length );
  674.     if ( *result == '\0' )
  675.         ParseCapability( capability, (unsigned char *) "MANUFACTURER:", result, result_length );
  676. }
  677.  
  678. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  679.     Name:        OpenBulkEndpoint
  680.  
  681.     Input Parameters:    
  682.         pPrinterPB
  683.         pb
  684.         refCon
  685.  
  686.     Output Parameters:
  687.         pb->usbReference    on (asynchronous) completion
  688.         
  689.     Description:
  690.         Asynchronous completion.
  691.  
  692.         Open a bulkIn or bulkOut endpoint
  693.  
  694.     Change History:
  695.         28 Feb 1998,    oja:        Original version.
  696. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  697. OSStatus
  698. OpenBulkEndpoint(
  699.     struct usbPrinterPBStruct    *pPrinterPB,
  700.     UInt32                            refCon
  701. )
  702. {
  703.  
  704.     OSStatus                        err;
  705.     USBEndPointDescriptor    *eDesc;
  706.     USBPB                            *pb = &pPrinterPB->pb;
  707.     //
  708.     // The params are set up correctly so open it
  709.     //    asynchronous completion will set usbReference to a pipe
  710.     //
  711.     switch (refCon)
  712.     {
  713.     case kOpenBulkOutPipe:
  714.         eDesc = FindEndpoint( pPrinterPB->interface, kUSBOut );
  715.         pPrinterPB->writeDescriptor = eDesc;
  716.         pb->usbFlags = kUSBOut;
  717.         break;
  718.     case kOpenBulkInPipe:
  719.         eDesc = FindEndpoint( pPrinterPB->interface, kUSBIn );
  720.         pPrinterPB->readDescriptor = eDesc;
  721.         pb->usbFlags = kUSBIn;
  722.         break;
  723.     default:
  724.         USBExpertFatalError(pPrinterPB->device, kUSBInternalErr, "\p" kStrPrinterClass "OpenEndpoint undefined refCon",1);
  725.         break;
  726.     }
  727.     pb->pbVersion = kUSBCurrentPBVersion;
  728.     pb->usbClassType = kUSBBulk;
  729.     pb->usbOther = eDesc->endpointAddress & ~0x80;
  730.     pb->usbWValue = USBToHostWord(eDesc->maxPacketSize);
  731.     pb->usbRefcon = refCon | kTransactionPending | kAsyncTransaction;
  732.  
  733.     err = USBOpenPipe( pb );
  734.     if(immediateError(err))
  735.         USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "OpenEndpoint Failed Open pipe", 0);
  736.  
  737.     return err;
  738. }
  739.  
  740. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  741.     Name:        DeregisterDevice
  742.  
  743.     Input Parameters:    
  744.         pPrinterPB
  745.  
  746.     Output Parameters:
  747.         <none>
  748.         
  749.     Description:
  750.         remove the device from the name registry
  751.  
  752.     Change History:
  753.         11 Jun 1998,    oja:        test from RegistryCStrEntryLookup was wrong direction
  754.         17 Apr 1998,    oja:        Original version.
  755. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  756. static OSStatus
  757. DeregisterDevice( struct usbPrinterPBStruct *pPrinterPB )
  758. {
  759.     OSStatus        err;
  760.     RegEntryID    self;
  761.  
  762.     RegistryEntryIDInit( &self );
  763.     err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->name , &self );
  764.     if ( err == noErr )
  765.     {
  766.         err = RegistryEntryDelete( &self);
  767.     }
  768.     RegistryEntryIDDispose(&self);
  769.     if (err == noErr &&  pPrinterPB->outRefNum != -1 )
  770.         err = TradRemoveDriver( pPrinterPB->outRefNum, false );
  771.     if (err == noErr &&  pPrinterPB->inRefNum != -1 )
  772.         err = TradRemoveDriver( pPrinterPB->inRefNum, false );
  773.     
  774.     return err;
  775. }
  776.  
  777. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  778.     Name:        RegisterDevice
  779.  
  780.     Input Parameters:    
  781.         pPrinterPB
  782.  
  783.     Output Parameters:
  784.         <none>
  785.         
  786.     Description:
  787.         add the device into the name registry; we can't insert just the node
  788.         if the parent nodes aren't present.
  789.  
  790.         if it isn't present
  791.             insert the device CLASS into the registry
  792.         if it isn't present
  793.             insert the device MODEL into the registry
  794.         finally insert the device itself into the registry
  795.             we're careful to rename multiple devices
  796.  
  797.     Change History:
  798.         16 Jul 1998,    oja:        fix params to sprintf
  799.          8 Jun 1998,    oja:        don't use register param (CW build)
  800.         26 Mar 1998,    oja:        only register significant part of drvrNames 
  801.                                         log null model name to Expert
  802.                                         register command set 
  803.         28 Feb 1998,    oja:        Original version.
  804. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  805. static OSStatus
  806. RegisterDevice( struct usbPrinterPBStruct *pPrinterPB )
  807. {
  808.     //
  809.     //    add the device into the name registry
  810.     //    if it isn't present
  811.     //        insert the device CLASS into the registry
  812.     //    if it isn't present
  813.     //        insert the device MODEL into the registry
  814.     //    finally insert the device itself into the registry
  815.     //        we're careful to rename multiple devices
  816.     //
  817.     Str255        identification,
  818.                     devclass,
  819.                     model,
  820.                     commands;
  821.     RegEntryID    parent, where, self;
  822.     OSStatus        err;
  823.     int            model_length,
  824.                     command_length,
  825.                     class_length;
  826.  
  827.     class_length = sizeof(devclass);
  828.     GetClass( pPrinterPB->capabilityString, devclass, &class_length );
  829.  
  830.     command_length = sizeof(commands);
  831.     GetCommandSet(pPrinterPB->capabilityString, commands, &command_length );
  832.  
  833.     strcpy( (char *)pPrinterPB->name, (char *)"Devices:device-tree:" );
  834.     strcat( (char *)pPrinterPB->name, (char *)devclass );
  835.     
  836.     RegistryEntryIDInit( &where );
  837.     err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->name, &where );
  838.     if ( err == nrPathNotFound ) 
  839.     {
  840.         //    class not in registry
  841.         //        create a node for all devices of this CLASS
  842.         //
  843.         RegistryEntryIDInit( &parent );
  844.         err = RegistryCStrEntryLookup( nil, "Devices:device-tree:" , &parent );
  845.         if ( err == noErr )
  846.             err = RegistryCStrEntryCreate( nil, (char const *) pPrinterPB->name, &where );
  847.         RegistryEntryIDDispose(&parent);
  848.  
  849.     }
  850.     //
  851.     //    add this model into the name registry of this class
  852.     //
  853.     if ( err == noErr )
  854.     {
  855.         model_length = sizeof(model);
  856.         GetModel( pPrinterPB->capabilityString, model, &model_length );
  857.         if ( model_length != 0 )
  858.         {
  859.             strcpy( (char *)pPrinterPB->name, "Devices:device-tree:" );
  860.             strcat( (char *)pPrinterPB->name, (char *)devclass );
  861.             strcat( (char *)pPrinterPB->name, ":" );
  862.             strcat( (char *)pPrinterPB->name, (char *)model );
  863.             RegistryEntryIDInit( &self );
  864.             err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->name , &self );
  865.             if ( err != noErr )
  866.             {
  867.                 // model not in registry
  868.                 err = RegistryCStrEntryCreate( nil, (char const *) pPrinterPB->name, &self );
  869.             }
  870.             RegistryEntryIDDispose(&self);
  871.         }
  872.     }
  873.     //
  874.     //    add this instance of this model of this class
  875.     //        into the name registry
  876.     //
  877.     if ( model_length == 0  )
  878.     {
  879.         //
  880.         //    possibly the cable isn't firmly connected or the printer isn't switched on
  881.         //
  882.         err = kUSBInternalErr;
  883.         USBExpertFatalError(pPrinterPB->device, err, kStrPrinterClass "\pModel undefined", 0);
  884.     }
  885.     if ( err == noErr )
  886.     {
  887.         //
  888.         //    start off by identifying the device simply by the model name
  889.         //        increment the numeric suffix until we successfully registry the device
  890.         //
  891.         Str32    suffix;
  892.         int    numeric_suffix;
  893.  
  894.         strcpy( (char *)identification, (char *)model );
  895.         RegistryEntryIDInit( &self );
  896.         for ( numeric_suffix = 1; numeric_suffix < MAX_SUFFIX; ++numeric_suffix )
  897.         {
  898.             strcpy( (char *)pPrinterPB->name, "Devices:device-tree:" );
  899.             strcat( (char *)pPrinterPB->name, (char *)devclass );
  900.             strcat( (char *)pPrinterPB->name, ":" );
  901.             strcat( (char *)pPrinterPB->name, (char *)model );
  902.             strcat( (char *)pPrinterPB->name, ":" );
  903.             strcat( (char *)pPrinterPB->name, (char *)identification );
  904.             err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->name , &self );
  905.             if ( err != noErr )
  906.             {
  907.                 // enter device in registry
  908.                 err = RegistryCStrEntryCreate( nil, (char const *) pPrinterPB->name, &self );
  909.                 if ( err == noErr )
  910.                     err = RegistryPropertyCreate( &self, "drvrOut", &pPrinterPB->driverOutName, 1 + pPrinterPB->driverOutName[0] );
  911.                 if ( err == noErr )
  912.                     err = RegistryPropertyCreate( &self, "outRef", &pPrinterPB->outRefNum, sizeof(pPrinterPB->outRefNum) );
  913.                 if ( err == noErr )
  914.                     err = RegistryPropertyCreate( &self, "drvrIn", &pPrinterPB->driverInName, 1 + pPrinterPB->driverInName[0] );
  915.                 if ( err == noErr )
  916.                     err = RegistryPropertyCreate( &self, "inRef", &pPrinterPB->inRefNum, sizeof(pPrinterPB->inRefNum) );
  917.                 if ( err == noErr )
  918.                     err = RegistryPropertyCreate( &self, "privateData", &pPrinterPB, sizeof(pPrinterPB) );
  919.                 if ( err == noErr )
  920.                     err = RegistryPropertyCreate( &self, "read", &pPrinterPB->r, sizeof(QueueUSBReadUPP) );
  921.                 if ( err == noErr )
  922.                     err = RegistryPropertyCreate( &self, "write", &pPrinterPB->w, sizeof(QueueUSBWriteUPP) );
  923.                 if ( err == noErr && command_length > 0 )
  924.                     err = RegistryPropertyCreate( &self, "command-set", &commands, command_length );
  925.                 break;
  926.             }
  927.             //
  928.             //    if this name didn't succeed
  929.             //        try the next numeric suffix
  930.             //
  931.             sprintf( (char *)suffix, " %d", numeric_suffix );
  932.             strcpy( (char *)identification, (char *)model );
  933.             strcat( (char *)identification, (char *)suffix );
  934.         }
  935.         RegistryEntryIDDispose(&self);
  936.     }
  937.     USBExpertStatus( pPrinterPB->device, pPrinterPB->name, err );
  938.     RegistryEntryIDDispose(&where);
  939.  
  940.     return err;
  941. }
  942.  
  943. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  944.     Name:        LoadResources
  945.  
  946.     Input Parameters:
  947.         pPrinterPB            pointer to class driver's private storage
  948.         
  949.     Output Parameters:
  950.         OSStatus                resource load error
  951.         
  952.     Description:
  953.         Initialize time is the only safe time to to load resources from our file.
  954.         Here's where we load resources and detach them from the resource manager.
  955.         Later we'll use these private copies instead of GetResource calls.
  956.         
  957.         Using the file spec that we got from the CFMInitialization routine, open
  958.         our resource fork.
  959.  
  960.     Change History:
  961.         11 Jun 1998,    oja:        removed hardcoded filename, use printerClassDriverFileSpec
  962.         20 Mar 1998,    oja:        Original version.
  963. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  964. static OSStatus
  965. LoadResources( struct usbPrinterPBStruct *pPrinterPB )
  966. {
  967.     short            rf = -1;                // class driver resource fork
  968.     OSStatus        err;
  969.  
  970.     //
  971.     //    open the resource fork of this class driver
  972.     //
  973.     rf = FSpOpenResFile( &printerClassDriverFileSpec,fsRdPerm );
  974.     err = ResError();
  975.     
  976.     //
  977.     //    load the DRVR that we'll stick in the unit table
  978.     //
  979.     pPrinterPB->hDrvr = NULL;
  980.     if ( err == noErr )
  981.     {
  982.         pPrinterPB->hDrvr = (DRVRHeaderHandle) Get1Resource( 'DRVR',  kUSBParallelDrvrRsrcID );
  983.         if ( pPrinterPB->hDrvr != NULL )
  984.             DetachResource( (Handle) pPrinterPB->hDrvr );
  985.         err = ResError();
  986.     }
  987.     
  988.     if ( rf != -1 )
  989.         CloseResFile( rf );
  990.     
  991.     return err;
  992. }
  993.  
  994. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  995.     Name:        InstallDrivers
  996.  
  997.     Input Parameters:
  998.         pPrinterPB
  999.         
  1000.     Output Parameters:
  1001.         OSStatus            error code
  1002.         
  1003.     Description:
  1004.         install read and write drivers in the unit table
  1005.             we have separate drivers so that we can support a full-duplex protocol
  1006.         rename the driver we just installed (so multiple copies don't conflict)
  1007.         We use the DRVR -refnum-1 so that the driver name has the same hex chars
  1008.             as the driver number (for manual verification in MacsBug)
  1009.  
  1010.     Change History:
  1011.         13 Jul 1998,    oja:        init err to noErr
  1012.         26 Mar 1998,    oja:        Use refnum -1, use infix location to enumerate
  1013.                                         DRVR
  1014.         28 Feb 1998,    oja:        Original version.
  1015. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1016. static OSStatus
  1017. InstallDrivers( struct usbPrinterPBStruct *pPrinterPB )
  1018. {
  1019.     //
  1020.     //    install the driver in the unit table
  1021.     //    rename the driver we just installed (so multiple copies don't conflict)
  1022.     //    
  1023.     short            refNum;                // DRVR refNum
  1024.     OSStatus        err =  paramErr;    // couldn't find driver
  1025.  
  1026.     if ( pPrinterPB->hDrvr != NULL )
  1027.         err = TradInstallDriverFromHandle( pPrinterPB->hDrvr, kMinDrvrUnitNumber, TradHighestUnitNumber() + 1, &pPrinterPB->outRefNum );
  1028.  
  1029.     if ( err == noErr )
  1030.     {
  1031.         UnitNumber        unit;
  1032.         DriverFlags        flags;
  1033.         DRVRHeaderPtr    hdr;
  1034.         unsigned char    *suffix,        // append "In" and "Out"
  1035.                             *infix;        // driver reference number follows the ".USB"
  1036.  
  1037.         TradGetDriverInformation( pPrinterPB->outRefNum, &unit, &flags, pPrinterPB->driverOutName, &hdr );
  1038.         BlockMove( pPrinterPB->driverOutName, pPrinterPB->driverInName, 1 + pPrinterPB->driverOutName[0] );
  1039.         
  1040.         suffix = pPrinterPB->driverOutName + pPrinterPB->driverOutName[0] - 2;
  1041.         infix = pPrinterPB->driverOutName + kDrvrFirstDigit;
  1042.         infix[0] = HiHex( -pPrinterPB->outRefNum -1 );
  1043.         infix[1] = LoHex( -pPrinterPB->outRefNum -1 );
  1044.         suffix[0] = 'O';
  1045.         suffix[1] = 'u';
  1046.         suffix[2] = 't';
  1047.         TradRenameDriver( pPrinterPB->outRefNum, pPrinterPB->driverOutName );
  1048.         //
  1049.         //    set the driver data to point to our parameter block
  1050.         //
  1051.         err = OpenDriver( pPrinterPB->driverOutName, &refNum );
  1052.         if ( err == noErr )
  1053.         {
  1054.             struct usbPrinterPBStruct *param = pPrinterPB;
  1055.             err = Control( refNum, kDrvrPrivateSetStorage, ¶m );
  1056.             CloseDriver( refNum );
  1057.         }
  1058.         err = TradInstallDriverFromHandle( pPrinterPB->hDrvr, kMinDrvrUnitNumber, TradHighestUnitNumber() + 1, &pPrinterPB->inRefNum );
  1059.         if ( err == noErr )
  1060.         {
  1061.             
  1062.             suffix = pPrinterPB->driverInName + pPrinterPB->driverInName[0] - 1;
  1063.             infix = pPrinterPB->driverInName + kDrvrFirstDigit;
  1064.             infix[0] = HiHex( -pPrinterPB->inRefNum -1 );
  1065.             infix[1] = LoHex( -pPrinterPB->inRefNum -1 );
  1066.             suffix[0] = 'I';
  1067.             suffix[1] = 'n';
  1068.             TradRenameDriver( pPrinterPB->inRefNum, pPrinterPB->driverInName );
  1069.             //
  1070.             //    set the driver data to point to our parameter block
  1071.             //
  1072.             err = OpenDriver( pPrinterPB->driverInName, &refNum );
  1073.             if ( err == noErr )
  1074.             {
  1075.                 struct usbPrinterPBStruct *param = pPrinterPB;
  1076.                 err = Control( refNum, kDrvrPrivateSetStorage, ¶m );
  1077.                 CloseDriver( refNum );
  1078.             }
  1079.         }
  1080.     }
  1081.  
  1082.     return err;
  1083. }
  1084.  
  1085. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1086.     Name:        GetCapability
  1087.  
  1088.     Input Parameters:    
  1089.         
  1090.     Output Parameters:
  1091.         
  1092.     Description:
  1093.         Asynchronous completion.
  1094.  
  1095.     Change History:
  1096.         28 Feb 1998,    oja:        Original version.
  1097. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1098. static void
  1099. GetCapability( struct usbPrinterPBStruct *pPrinterPB, unsigned char *p, int length )
  1100. {
  1101.     //
  1102.     //    queue a transaction to retrieve the 1284 capability string
  1103.     //        we must have assigned the interface by this point since the capability string
  1104.     //        may vary with the interface
  1105.     //
  1106.     OSStatus        err;
  1107.     USBPB            *pb = &pPrinterPB->pb;
  1108.     
  1109.     pb->usbBMRequestType = USBMakeBMRequestType(kUSBIn, kUSBClass, kUSBInterface);
  1110.  
  1111.     pb->usbBRequest = kUSBPrintClassGetDeviceID;
  1112.     pb->usbWValue = (pPrinterPB->config)->configValue;        // configuration
  1113.     pb->usbWIndex = ((pPrinterPB->interface)->interfaceNumber<<8) | (pPrinterPB->interface)->alternateSetting;
  1114.  
  1115.     pb->usbReqCount = length;
  1116.     pb->usbBuffer = p;
  1117.  
  1118.     pb->usbStatus = 0;
  1119.     pb->usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  1120.     pb->usbRefcon |= kTransactionPending | kAsyncTransaction;
  1121.  
  1122.     err = USBDeviceRequest(pb);
  1123.     if(immediateError(err))
  1124.     {
  1125.         USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "GetCapability", 0);
  1126.     }
  1127. }
  1128.  
  1129. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1130.     Name:        IsLucentCable
  1131.  
  1132.     Input Parameters:    
  1133.         dev            USB device descriptor
  1134.         
  1135.     Output Parameters:
  1136.         Return 1 if the USB device is a USB-parallel cable
  1137.         
  1138.     Description:
  1139.         
  1140.  
  1141.     Change History:
  1142.         28 Feb 1998,    oja:        Original version.
  1143. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1144. static int
  1145. IsLucentCable( USBDeviceDescriptor    *dev )
  1146. {
  1147.     return ( USBToHostWord(dev->vendor) == 0x47E && USBToHostWord(dev->product) == 0x1001 )? 1: 0;
  1148. }
  1149.  
  1150.  
  1151. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1152.     Name:        SetInterface
  1153.  
  1154.     Input Parameters:    
  1155.         
  1156.     Output Parameters:
  1157.         
  1158.     Description:
  1159.         Asynchronous completion.
  1160.  
  1161.     Change History:
  1162.         28 Feb 1998,    oja:        Original version.
  1163. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1164. static void
  1165. SetInterface( USBPB *pb, int whichInterface, int whichAlternate )
  1166. {
  1167.     //
  1168.     //    the device is a Lucent USB-parallel cable
  1169.     //        select the bi-directional interface
  1170.     OSStatus    err;
  1171.  
  1172.     pb->usbBMRequestType = USBMakeBMRequestType(kUSBOut, kUSBStandard, kUSBInterface);
  1173.  
  1174.     pb->usbBRequest = kUSBRqSetInterface;
  1175.     pb->usbWValue = whichAlternate;        // alternate setting
  1176.     pb->usbWIndex = whichInterface;        // interface
  1177.  
  1178.     pb->usbReqCount = 0;
  1179.     pb->usbBuffer = NULL;
  1180.  
  1181.     pb->usbStatus = 0;
  1182.     pb->usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  1183.     pb->usbRefcon |= kTransactionPending | kAsyncTransaction;
  1184.  
  1185.     err = USBDeviceRequest(pb);
  1186.     if(immediateError(err))
  1187.     {
  1188.         USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "SetInterface", 0);
  1189.     }
  1190. }
  1191.  
  1192. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1193.     Name:        GetInterface
  1194.  
  1195.     Input Parameters:    
  1196.         
  1197.     Output Parameters:
  1198.         
  1199.     Description:
  1200.         Asynchronous completion.
  1201.  
  1202.     Change History:
  1203.         28 Feb 1998,    oja:        Original version.
  1204. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1205. static void
  1206. GetInterface( USBPB *pb, UInt8 *alt )
  1207. {
  1208.     //
  1209.     //    make sure we account for any alternate interface currently in use by the device
  1210.     //
  1211.     OSStatus    err;
  1212.  
  1213.     pb->usbBMRequestType = USBMakeBMRequestType(kUSBIn, kUSBStandard, kUSBInterface);
  1214.  
  1215.     pb->usbBRequest = kUSBRqGetInterface;
  1216.     pb->usbWValue = 0; 
  1217.     pb->usbWIndex = 0;
  1218.  
  1219.     pb->usbReqCount = sizeof(UInt8);        // single byte is requested
  1220.     pb->usbBuffer = alt;
  1221.  
  1222.     pb->usbStatus = 0;
  1223.     pb->usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  1224.     pb->usbRefcon |= kTransactionPending | kAsyncTransaction;
  1225.  
  1226.     err = USBDeviceRequest(pb);
  1227.     if(immediateError(err))
  1228.     {
  1229.         USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "GetInterface", 0);
  1230.     }
  1231. }
  1232.  
  1233. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1234.     Name:        GetConfigurationDescriptor
  1235.  
  1236.     Input Parameters:    
  1237.         pb                        USB parameter block
  1238.         pConfiguration        storage for the reply
  1239.         length                number of bytes allocated for the reply
  1240.         
  1241.     Output Parameters:
  1242.         pConfiguration        the device's configuration descriptor (possibly truncated)
  1243.         
  1244.     Description:
  1245.         Asynchronous completion.
  1246.  
  1247.         Retrieve the device's configuration descriptor. Note that we may not get
  1248.         the full configuration--the client must read the length in the reply and
  1249.         determine if the call successfully completed retrieval of the full config-
  1250.         uration descriptor.
  1251.  
  1252.     Change History:
  1253.         28 Feb 1998,    oja:        Original version.
  1254. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1255. static void
  1256. GetConfigurationDescriptor(
  1257.     USBPB *pb,
  1258.     USBConfigurationDescriptorPtr pConfiguration, 
  1259.     int length
  1260. )
  1261. {
  1262.     OSStatus    err;
  1263.  
  1264.     pb->usbBMRequestType = USBMakeBMRequestType(kUSBIn, kUSBStandard, kUSBDevice);
  1265.  
  1266.     pb->usbBRequest = kUSBRqGetDescriptor;
  1267.     pb->usbWValue = (kUSBConfDesc<<8) + 0; 
  1268.     pb->usbWIndex = 0;    //language
  1269.  
  1270.     pb->usbReqCount = length;
  1271.     pb->usbBuffer = pConfiguration;
  1272.  
  1273.     pb->usbStatus = 0;
  1274.     pb->usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  1275.     pb->usbRefcon |= kTransactionPending | kAsyncTransaction;
  1276.  
  1277.     err = USBDeviceRequest(pb);
  1278.     if(immediateError(err))
  1279.     {
  1280.         USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "GetConfigurationDescriptor", 0);
  1281.     }
  1282. }
  1283.  
  1284. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1285.     Name:        ReadCompletion
  1286.  
  1287.     Input Parameters:    
  1288.         pb                        USB parameter block
  1289.         
  1290.     Output Parameters:
  1291.         <none>
  1292.  
  1293.     Description:
  1294.         USB read requests complete here.
  1295.         We dequeue the MacOS DRVR read requests
  1296.  
  1297.     Change History:
  1298.          8 Jun 1998,    oja:        clear stalls on error
  1299.         28 Feb 1998,    oja:        Original version.
  1300. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1301. static void
  1302. ReadCompletion(USBPB *pb)
  1303. {
  1304.     //    call the user completion routine
  1305.     struct usbPrinterPBStruct    *pPrinterPB = (struct usbPrinterPBStruct *) pb->usbRefcon;
  1306.     IOParamPtr                        clientParam = pPrinterPB->readDrvr.pb;
  1307.  
  1308.     clientParam->ioActCount = pb->usbActCount;
  1309.  
  1310.     if ( pb->usbStatus != noErr ) 
  1311.     {
  1312.         IF_DEBUG( USBExpertStatus(pPrinterPB->device, USBStatusStr(pb->usbStatus, kPString) , pb->usbStatus ) );
  1313.         USBClearPipeStallByReference(pb->usbReference);  // we got an error, try to clear any stalls
  1314.     }
  1315.     clientParam->ioResult = pb->usbStatus;
  1316.  
  1317.     if ( pPrinterPB->writeDrvr.ctl != NULL )
  1318.         CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, pb->usbStatus, clientParam, pPrinterPB->readDrvr.ctl ); 
  1319.  
  1320.     pb->usbCompletion = NULL;    // checked by Finalize
  1321. }
  1322.  
  1323. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1324.     Name:        WriteCompletion
  1325.  
  1326.     Input Parameters:    
  1327.         pb                        USB parameter block
  1328.         
  1329.     Output Parameters:
  1330.         <none>
  1331.  
  1332.     Description:
  1333.         USB write requests complete here.
  1334.         We dequeue the MacOS DRVR write requests
  1335.  
  1336.     Change History:
  1337.         28 Feb 1998,    oja:        Original version.
  1338. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1339. static void
  1340. WriteCompletion(USBPB *pb)
  1341. {
  1342.     //    call the user completion routine
  1343.     struct usbPrinterPBStruct
  1344.                     *pPrinterPB =  (struct usbPrinterPBStruct    *) pb->usbRefcon;
  1345.     IOParamPtr     clientParam = pPrinterPB->writeDrvr.pb;
  1346.  
  1347.     clientParam->ioActCount = pb->usbActCount;
  1348.  
  1349.     if ( pb->usbStatus != noErr ) 
  1350.     {
  1351.         USBClearPipeStallByReference(pb->usbReference);  // we got an error, try to clear any stalls
  1352.  
  1353.         IF_DEBUG( USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "WriteCompletion Error" , pb->usbStatus ) );
  1354.         IF_DEBUG( USBExpertStatus(pPrinterPB->device, USBStatusStr(pb->usbStatus, kPString) , pb->usbStatus ) );
  1355.  
  1356.         clientParam->ioResult = pb->usbStatus;
  1357.     }
  1358.  
  1359.     if ( pPrinterPB->writeDrvr.ctl != NULL )
  1360.         CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, pb->usbStatus, clientParam, pPrinterPB->writeDrvr.ctl ); 
  1361.     
  1362.     pb->usbCompletion = NULL;    // checked by Finalize
  1363.  
  1364. }
  1365.  
  1366. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1367.     Name:        QueueRead
  1368.  
  1369.     Input Parameters:    
  1370.         pb                        MacOS device manager parameter block
  1371.         ctl                    device manager dCtl block
  1372.         pPrinterPB            current printing device class's storage
  1373.         
  1374.     Output Parameters:
  1375.         <none>
  1376.  
  1377.     Description:
  1378.         MacOS DRVR read requests are re-queued here to the USB
  1379.         Since we only allow one read request pending at a time, we're able
  1380.         to use the USB refCon to point to our class driver's storage.
  1381.  
  1382.     Change History:
  1383.         28 Feb 1998,    oja:        Original version.
  1384. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1385. void
  1386. QueueRead( IOParamPtr pb, DCtlPtr ctl, struct usbPrinterPBStruct *pPrinterPB )
  1387. {    
  1388.     OSStatus    err;
  1389.     USBPB        *usbprint = &pPrinterPB->in;
  1390.     
  1391. #if DEBUG
  1392.     Str255    text;
  1393.  
  1394.     sprintf( (char *)text, " PrinterClass Read: %d @ %08x", pb->ioReqCount, pb->ioBuffer );
  1395.     text[0] = strlen((char *)text); // c2pstr
  1396.     USBExpertStatus(pPrinterPB->device, text, usbprint->usbStatus );
  1397. #endif
  1398.     if ( printerClassRecord.terminating )
  1399.         pb->ioResult = abortErr;
  1400.     else
  1401.     {
  1402.  
  1403.         pPrinterPB->readDrvr.pb= pb;
  1404.         pPrinterPB->readDrvr.ctl = ctl;
  1405.         if ( pPrinterPB->readPipe != NULL )
  1406.         {
  1407.             SetNullUSBParamBlock( pPrinterPB->readPipe,  usbprint );
  1408.             usbprint->usbBuffer = pb->ioBuffer;
  1409.             usbprint->usbReqCount = pb->ioReqCount;
  1410.             usbprint->usbRefcon = (unsigned long) pPrinterPB;
  1411.         
  1412.             usbprint->usbCompletion = (USBCompletion) ReadCompletion;
  1413.             
  1414.             pb->ioResult = ioInProgress;
  1415.             err = USBBulkRead( usbprint );
  1416.             if ( immediateError(err) )
  1417.             {
  1418.                 IF_DEBUG( DebugStr( USBStatusStr(err, kPString) ) );
  1419.                 usbprint->usbStatus = err;
  1420.             }
  1421.         }
  1422.     }
  1423. }
  1424.  
  1425. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1426.     Name:        QueueWrite
  1427.  
  1428.     Input Parameters:    
  1429.         pb                        MacOS device manager parameter block
  1430.         ctl                    device manager dCtl block
  1431.         pPrinterPB            current printing device class's storage
  1432.         
  1433.     Output Parameters:
  1434.         <none>
  1435.  
  1436.     Description:
  1437.         MacOS DRVR write requests are re-queued here to the USB
  1438.         Since we only allow one read request pending at a time, we're able
  1439.         to use the USB refCon to point to our class driver's storage.
  1440.  
  1441.     Change History:
  1442.         28 Feb 1998,    oja:        Original version.
  1443. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1444. void
  1445. QueueWrite( IOParamPtr pb, DCtlPtr ctl, struct usbPrinterPBStruct *pPrinterPB )
  1446. {
  1447.     OSStatus    err;
  1448.     USBPB        *usbprint = &pPrinterPB->out;
  1449.     
  1450. #ifdef DEBUG
  1451.     Str255    text;
  1452.     sprintf( (char *)text, " PrinterClass Write: %d @ %08x", pb->ioReqCount, pb->ioBuffer );
  1453.     text[0] = strlen((char *)text); // c2pstr
  1454.     USBExpertStatus(pPrinterPB->device, text, usbprint->usbStatus );
  1455. #endif
  1456.  
  1457.     if ( printerClassRecord.terminating )
  1458.         pb->ioResult = abortErr;
  1459.     else
  1460.     {
  1461.         pPrinterPB->writeDrvr.pb = pb;
  1462.         pPrinterPB->writeDrvr.ctl = ctl;
  1463.         if ( pPrinterPB->writePipe != NULL )
  1464.         {
  1465.             SetNullUSBParamBlock( pPrinterPB->writePipe,  usbprint );
  1466.             usbprint->usbBuffer = pb->ioBuffer;
  1467.             usbprint->usbReqCount = pb->ioReqCount;
  1468.             usbprint->usbRefcon = (unsigned long) pPrinterPB;
  1469.         
  1470.             usbprint->usbCompletion = (USBCompletion) WriteCompletion;
  1471.              
  1472.             pb->ioResult = ioInProgress;
  1473.     
  1474.             err = USBBulkWrite( usbprint );
  1475.             if ( immediateError(err) )
  1476.             {
  1477.                 IF_DEBUG( DebugStr( USBStatusStr(err, kPString) ) );
  1478.                 usbprint->usbStatus = err;
  1479.             }
  1480.         }
  1481.     }
  1482. }
  1483.  
  1484.  
  1485. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1486.     Name:        Abort
  1487.  
  1488.     Input Parameters:    
  1489.         refNum            DRVR refnum
  1490.         pPrinterPB        current printing device class's storage
  1491.  
  1492.     Output Parameters:
  1493.         
  1494.     Description:
  1495.         Asynchronous completion.
  1496.  
  1497.     Change History:
  1498.         28 Feb 1998,    oja:        Original version.
  1499. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1500. OSStatus
  1501. Abort( DriverRefNum refNum, struct usbPrinterPBStruct *pPrinterPB )
  1502. {
  1503.     USBPipeRef    whichPipe;
  1504.  
  1505.     whichPipe = refNum == pPrinterPB->outRefNum? pPrinterPB->writePipe: pPrinterPB->readPipe;
  1506.     
  1507.     return USBAbortPipeByReference( whichPipe );
  1508. }
  1509.  
  1510.  
  1511. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1512.     Name:        CompletionProc
  1513.  
  1514.     Input Parameters:    
  1515.         pb                    USB param block ptr
  1516.     
  1517.     Output Parameters:
  1518.         
  1519.     Description:
  1520.         Asynchronous completion routine for DRVR requests.
  1521.  
  1522.     Change History:
  1523.         11 Jun 1998,    oja:        Original version.
  1524. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1525. static void 
  1526. CompletionProc(USBPB *pb)
  1527. {
  1528.     //    call the user completion routine
  1529.     struct usbPrinterPBStruct
  1530.                     *pPrinterPB = (struct usbPrinterPBStruct    *) pb->usbRefcon;
  1531.     IOParamPtr     clientParam = pPrinterPB->statusDrvr.pb;
  1532.  
  1533.     clientParam->ioActCount = pb->usbActCount;
  1534.  
  1535.     if ( pb->usbStatus != noErr ) 
  1536.     {
  1537.         USBClearPipeStallByReference(pb->usbReference);  // we got an error, try to clear any stalls
  1538.  
  1539.         IF_DEBUG( USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "CompletionProc Error" , pb->usbStatus ) );
  1540.         IF_DEBUG( USBExpertStatus(pPrinterPB->device, USBStatusStr(pb->usbStatus, kPString) , pb->usbStatus ) );
  1541.  
  1542.         clientParam->ioResult = pb->usbStatus;
  1543.     }
  1544.  
  1545.     if ( pPrinterPB->statusDrvr.ctl != NULL )
  1546.         CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, pb->usbStatus, clientParam, pPrinterPB->statusDrvr.ctl ); 
  1547. }
  1548.  
  1549. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1550.     Name:        CentronicsStatus
  1551.  
  1552.     Input Parameters:    
  1553.         pb                        MacOS device manager parameter block
  1554.         ctl                    device manager dCtl block
  1555.         pPrinterPB            current printing device class's storage
  1556.  
  1557.     Output Parameters:
  1558.         pStatusByte        
  1559.         
  1560.     Description:
  1561.         setup the device request for a USB printer class request one byte status.
  1562.  
  1563.     Change History:
  1564.         29 Jun 1998,    oja:        called from StatusControlRequests, change params
  1565.         26 Jun 1998,    oja:        changed params to be consistent w/ Read & Write
  1566.         11 Jun 1998,    oja:        Original version.
  1567. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1568. static void
  1569. CentronicsStatus( USBPB *usbprint, Ptr buffer, short interfaceNumber )
  1570. {
  1571.     usbprint->usbBMRequestType = USBMakeBMRequestType(kUSBIn, kUSBClass, kUSBInterface);
  1572.  
  1573.     usbprint->usbBRequest = kUSBPrintClassGetCentronicsStatus;
  1574.     usbprint->usbWValue = 0;
  1575.     usbprint->usbWIndex = interfaceNumber;
  1576.  
  1577.     usbprint->usbReqCount = 1;
  1578.     usbprint->usbBuffer = buffer;
  1579. }
  1580.  
  1581. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1582.     Name:        SoftReset
  1583.  
  1584.     Input Parameters:    
  1585.         usbprint                USB param block
  1586.         interfaceNumber
  1587.  
  1588.     Output Parameters:
  1589.         
  1590.     Description:
  1591.         Setup the device request for a USB printer class request soft reset.
  1592.  
  1593.     Change History:
  1594.         29 Jun 1998,    oja:        called from StatusControlRequests, change params
  1595.         26 Jun 1998,    oja:        changed params to be consistent w/ Read & Write
  1596.         11 Jun 1998,    oja:        Original version.
  1597. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1598. void
  1599. SoftReset( USBPB *usbprint, short interfaceNumber )
  1600. {
  1601.     usbprint->usbBMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBOther);
  1602.  
  1603.     usbprint->usbBRequest = kUSBPrintClassSoftReset;
  1604.     usbprint->usbWValue = 0;
  1605.     usbprint->usbWIndex = interfaceNumber;
  1606.  
  1607.     usbprint->usbReqCount = 0;
  1608.     usbprint->usbBuffer = NULL;
  1609.  
  1610. }
  1611.  
  1612. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1613.     Name:        CapabilityRequest
  1614.  
  1615.     Input Parameters:    
  1616.         usbprint            USB parameter block
  1617.         p                    result pointer
  1618.         length            amount of data allocated
  1619.         config
  1620.         interfaceNum
  1621.         alternateSetting
  1622.         
  1623.  
  1624.     Output Parameters:
  1625.         p                    result pointer
  1626.         length            amount of data allocated
  1627.         
  1628.     Description:
  1629.         setup the device request for a USB printer class request 1284 id string.
  1630.  
  1631.     Change History:
  1632.         29 Jun 1998,    oja:        called from StatusControlRequests, change params
  1633.         26 Jun 1998,    oja:        changed params to be consistent w/ Read & Write
  1634.         11 Jun 1998,    oja:        Original version.
  1635. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1636. void
  1637. CapabilityRequest( USBPB *pb, Ptr p, long length, short configValue, short interfaceNumber, short alternateSetting  )
  1638. {
  1639.  
  1640.     pb->usbBMRequestType = USBMakeBMRequestType(kUSBIn, kUSBClass, kUSBInterface);
  1641.  
  1642.     pb->usbBRequest = kUSBPrintClassGetDeviceID;
  1643.     pb->usbWValue = configValue;        // configuration
  1644.     pb->usbWIndex = (interfaceNumber<<8) | alternateSetting;
  1645.  
  1646.     pb->usbReqCount = length;
  1647.     pb->usbBuffer = p;
  1648.  
  1649. }
  1650.  
  1651. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1652.     Name:        StatusControlRequests
  1653.  
  1654.     Input Parameters:    
  1655.         pb                        MacOS device manager parameter block
  1656.         ctl                    device manager dCtl block
  1657.         pPrinterPB            current printing device class's storage
  1658.  
  1659.     Output Parameters:
  1660.         
  1661.     Description:
  1662.         Asynchronous completion.
  1663.  
  1664.     Change History:
  1665.         26 Jun 1998,    oja:        changed params to be consistent w/ Read & Write
  1666.         11 Jun 1998,    oja:        Original version.
  1667. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1668.  
  1669. void
  1670. ControlStatusRequests( IOParamPtr pb, DCtlPtr ctl, struct usbPrinterPBStruct *pPrinterPB )
  1671. {
  1672.  
  1673.     //
  1674.     //    queue a transaction to retrieve the centronics status
  1675.     //
  1676.     OSStatus        err;
  1677.     USBPB            *usbprint = &pPrinterPB->pb;
  1678.     Boolean        dosomething = false;
  1679.     
  1680. #if DEBUG
  1681.     Str255        text;
  1682.  
  1683.     sprintf( (char *)text, " PrinterClass ControlStatus: %d", ((CntrlParam *) pb)->csCode );
  1684.     text[0] = strlen((char *)text); // c2pstr
  1685.     USBExpertStatus(pPrinterPB->device, text, usbprint->usbStatus );
  1686. #endif
  1687.  
  1688.     switch( ((CntrlParam *) pb)->csCode )
  1689.     {
  1690.     case kDrvrCentronicsStatus:
  1691.         dosomething = true;
  1692.         CentronicsStatus( usbprint,  *((Ptr *)((CntrlParam *) pb)->csParam), (pPrinterPB->interface)->interfaceNumber );
  1693.         break;
  1694.     case kDrvr1284IdString:
  1695.         dosomething = true;
  1696.         CapabilityRequest( usbprint,
  1697.                                 *((Ptr *)((CntrlParam *) pb)->csParam),
  1698.                                 *((long *) &((CntrlParam *) pb)->csParam[4]),
  1699.                                 (pPrinterPB->config)->configValue,        // configuration
  1700.                                 (pPrinterPB->interface)->interfaceNumber,
  1701.                                 (pPrinterPB->interface)->alternateSetting );
  1702.         break;
  1703.     case kDrvrSoftReset:
  1704.         dosomething = true;
  1705.         SoftReset( usbprint, (pPrinterPB->interface)->interfaceNumber );
  1706.         break;
  1707.     default:
  1708.         break;
  1709.     }
  1710.  
  1711.     if ( !dosomething )
  1712.         pb->ioResult = paramErr;
  1713.     else
  1714.     {
  1715.         usbprint->usbStatus = 0;
  1716.         usbprint->usbCompletion = (USBCompletion)CompletionProc;
  1717.         usbprint->usbRefcon = (unsigned long) pPrinterPB;
  1718.     
  1719.         pb->ioResult = ioInProgress;
  1720.         pPrinterPB->statusDrvr.pb = pb;
  1721.         pPrinterPB->statusDrvr.ctl = ctl;
  1722.     
  1723.         err = USBDeviceRequest(usbprint);
  1724.         if(immediateError(err))
  1725.         {
  1726.             USBExpertFatalError(usbprint->usbReference, err, "\p" kStrPrinterClass "StatusControlRequests", 0);
  1727.             pb->ioResult = err;
  1728.         }
  1729.     }
  1730. }
  1731.  
  1732.  
  1733. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1734.     Name:        PrinterDeviceCompletionProc
  1735.  
  1736.     Input Parameters:    
  1737.         pb                refCon tells which state we're completing
  1738.  
  1739.     Output Parameters:
  1740.         <none>
  1741.         
  1742.     Description:
  1743.         Complete asynch transactions initiated by PrinterDeviceInitiateTransaction.
  1744.  
  1745.     Change History:
  1746.         15 May 1998,    oja:        added missing break for GetCapabilityString
  1747.                                         reworked GetFullConfiguration to properly handle case
  1748.                                             where there's only one interface
  1749.         26 Mar 1998,    oja:        set info 1 to DEBUG StateStr
  1750.                                         (distinguishes completion from initiate)
  1751.         28 Feb 1998,    oja:        Original version.
  1752. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1753.  
  1754. static void 
  1755. PrinterDeviceCompletionProc(USBPB *pb)
  1756. {
  1757.     register struct usbPrinterPBStruct *pPrinterPB;
  1758.     int                                            numInterface;
  1759.  
  1760.     pPrinterPB = (struct usbPrinterPBStruct *)(pb);
  1761.     pPrinterPB->transDepth--; 
  1762.     if ((pPrinterPB->transDepth < 0) || (pPrinterPB->transDepth > 1))
  1763.     {
  1764.         USBExpertFatalError(pPrinterPB->device, kUSBInternalErr, "\p" kStrPrinterClass "CompletionProc Illegal Transaction Depth", pPrinterPB->transDepth );
  1765.     }
  1766.  
  1767.     IF_DEBUG( USBExpertStatus(pPrinterPB->device, StateStr(pPrinterPB->pb.usbRefcon, kPString) , 1 ) );
  1768.     if((pPrinterPB->pb.usbStatus != noErr) && (pPrinterPB->pb.usbStatus != kUSBPending))
  1769.     {
  1770.         USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "    retry", pPrinterPB->pb.usbStatus);
  1771.  
  1772.         pPrinterPB->pb.usbRefcon &= ~(kTransactionPending + kAsyncTransaction + kReturnFromDriver);
  1773.         pPrinterPB->pb.usbRefcon |= kRetryTransaction;
  1774.         pPrinterPB->retryCount--;
  1775.         if (!pPrinterPB->retryCount)
  1776.         {
  1777.             USBExpertFatalError(pPrinterPB->device, kUSBInternalErr, "\p" kStrPrinterClass "Retry failed", pPrinterPB->pb.usbRefcon & ~kRetryTransaction);
  1778.             pPrinterPB->pb.usbRefcon = kUndefined | kReturnFromDriver;
  1779.             return;
  1780.         } else {
  1781.             pPrinterPB->pb.usbStatus = noErr; // let's retry one more time
  1782.         }
  1783.     }
  1784.     else
  1785.     {
  1786.         pPrinterPB->pb.usbRefcon &= ~kRetryTransaction;
  1787.         pPrinterPB->retryCount = kPrinterRetryCount;
  1788.     }
  1789.  
  1790.     if (pPrinterPB->pb.usbRefcon & kTransactionPending)             
  1791.     {            
  1792.         int    length;
  1793.     
  1794.         //
  1795.         //    advance to the next state
  1796.         //
  1797.         pPrinterPB->pb.usbRefcon &= ~(kTransactionPending + kAsyncTransaction + kReturnFromDriver);
  1798.         switch(pPrinterPB->pb.usbRefcon)
  1799.         {
  1800.             case kGetConfigurationDescriptor:
  1801.                 if ( pPrinterPB->pb.usbStatus == noErr )
  1802.                 {
  1803.                     pPrinterPB->pb.usbRefcon = kGetFullConfiguration;    
  1804.                 }
  1805.                 break;
  1806.                 
  1807.             case kGetFullConfiguration:
  1808.                 if ( pPrinterPB->pb.usbStatus == noErr )
  1809.                 {
  1810.                     pPrinterPB->interface = FindInterface( pPrinterPB->config, kUSBPrintClassProtocolBidirectional );
  1811.                     if ( pPrinterPB->interface == NULL )
  1812.                     {
  1813.                         pPrinterPB->interface = FindInterface( pPrinterPB->config, kUSBPrintClassProtocolUnidirectional );
  1814.                         if ( pPrinterPB->interface == NULL )
  1815.                             USBExpertFatalError(pPrinterPB->device, kUSBInternalErr, "\p" kStrPrinterClass "Can't find protocol", 0);
  1816.                     }
  1817.                     if ( pPrinterPB->interface != NULL )
  1818.                         pPrinterPB->interfaceOffset =  (char *) pPrinterPB->interface - (char *) pPrinterPB->config;
  1819.  
  1820.                     //
  1821.                     // if there's only one interface (or alternate) supported
  1822.                     //        skip the attempt to assign the interface
  1823.                     //
  1824.                     numInterface = CountInterface( pPrinterPB->config, kUSBPrintClass, kUSBPrintSubClass );
  1825.                     if ( numInterface <= 1 )
  1826.                         pPrinterPB->pb.usbRefcon = kGetCapabilityString;
  1827.                     else
  1828.                         pPrinterPB->pb.usbRefcon = kSetInterface;
  1829.                 }
  1830.                 break;
  1831.                 
  1832.             case kSetInterface:
  1833.                 if ( pPrinterPB->pb.usbStatus == noErr )
  1834.                 {
  1835.                     SetNullUSBParamBlock(pPrinterPB->device,  pb );
  1836.                     pPrinterPB->pb.usbRefcon = kGetCapabilityString;
  1837.                 }
  1838.                 break;
  1839.                 
  1840.             case kGetCapabilityString:
  1841.                 if ( pPrinterPB->pb.usbStatus == noErr )
  1842.                 {
  1843.                     //
  1844.                     //    In the short term (fall '98) several vendors are planning on shipping 
  1845.                     //        devices with a parallel port and using the Lucent USS-720 USB-to-parallel hardware.
  1846.                     //    Unfortunately this isn't an ideal solution from the USB perspective:
  1847.                     //        users can leave the printer off while the cable responds that there's
  1848.                     //        a printer connected. Then we have no way of using the DEVICE_ID
  1849.                     //        string to tag the printer and register it.
  1850.                     //    To alleviate this situation, we repeatedly poll the USS-720 if the DEVICE_ID
  1851.                     //        string is null. Every few seconds we'll retry this state.
  1852.                     //    At some point the user wants to print and switches on the printer. The class
  1853.                     //    driver then picks up from here and registers the device properly.
  1854.                     //
  1855.                     length = pPrinterPB->capabilityString[1] | (pPrinterPB->capabilityString[0] << 8);
  1856.                     if ( IsLucentCable( &pPrinterPB->desc ) && pPrinterPB->pb.usbActCount == 0 )
  1857.                         pPrinterPB->pb.usbRefcon = kDelayGetCapability;
  1858.                     else
  1859.                         pPrinterPB->pb.usbRefcon = kGetInterface;
  1860.                 }
  1861.                 else if ( pPrinterPB->pb.usbStatus == kUSBOverRunErr )
  1862.                 {
  1863.                     //
  1864.                     //    if we've haven't managed to read the whole capability string
  1865.                     //        we need to allocate memory and read it in by initiating kGetFullCapabilityString
  1866.                     //
  1867.                     length = pPrinterPB->capabilityString[1] | (pPrinterPB->capabilityString[0] << 8);
  1868.  
  1869.                     if ( length > sizeof(pPrinterPB->capability) &&
  1870.                             pPrinterPB->pb.usbRefcon == kGetCapabilityString )
  1871.                         pPrinterPB->pb.usbRefcon = kGetFullCapabilityString;
  1872.                 }
  1873.                 break;
  1874.             case kDelayGetCapability:
  1875.                 if ( pPrinterPB->pb.usbStatus == noErr )
  1876.                     pPrinterPB->pb.usbRefcon = kGetCapabilityString;
  1877.                 break;
  1878.             case kGetFullCapabilityString:
  1879.                 if ( pPrinterPB->pb.usbStatus == noErr )
  1880.                     pPrinterPB->pb.usbRefcon = kGetInterface;
  1881.                 break;
  1882.             case kGetInterface:
  1883.                 if ( pPrinterPB->pb.usbStatus == noErr )
  1884.                     pPrinterPB->pb.usbRefcon = kOpenBulkOutPipe;
  1885.                 break;
  1886.             case kOpenBulkOutPipe:
  1887.                 if ( pPrinterPB->pb.usbStatus == noErr )
  1888.                 {
  1889.                     pPrinterPB->writePipe = pPrinterPB->pb.usbReference; // remember the ref
  1890.                     pPrinterPB->out = pPrinterPB->pb;
  1891.                     SetNullUSBParamBlock( pPrinterPB->device, &pPrinterPB->pb );
  1892.  
  1893.                     if ( pPrinterPB->interface->interfaceProtocol == kUSBPrintClassProtocolBidirectional )
  1894.                         pPrinterPB->pb.usbRefcon = kOpenBulkInPipe;
  1895.                     else
  1896.                         pPrinterPB->pb.usbRefcon = kEnterNameRegistry;
  1897.                 }
  1898.                 break;
  1899.             case kOpenBulkInPipe:
  1900.                 if ( pPrinterPB->pb.usbStatus == noErr )
  1901.                 {
  1902.                     pPrinterPB->readPipe = pPrinterPB->pb.usbReference;
  1903.                     pPrinterPB->in = pPrinterPB->pb;
  1904.                     SetNullUSBParamBlock( pPrinterPB->device, &pPrinterPB->pb );
  1905.  
  1906.                     pPrinterPB->pb.usbRefcon = kEnterNameRegistry;
  1907.                 }
  1908.                 break;
  1909.             case kNilCompletion:
  1910.             case kEnterNameRegistry:
  1911.             default:
  1912.                 if ( pPrinterPB->pb.usbStatus == noErr )
  1913.                     pPrinterPB->pb.usbRefcon = kUndefined | kReturnFromDriver;
  1914.                 break;
  1915.         }
  1916.     }
  1917.  
  1918.     if ( pPrinterPB->terminating )
  1919.     {
  1920.         //    if we've been hot unplugged
  1921.         //        don't startup any new transactions
  1922.         //     allow PrintDriverFinalize to continue
  1923.         pPrinterPB->pb.usbRefcon = kReturnFromDriver;
  1924.     }
  1925.     else if ( pPrinterPB->pb.usbStatus == noErr )
  1926.     {
  1927.         if (!(pPrinterPB->pb.usbRefcon & kReturnFromDriver))
  1928.             PrinterDeviceInitiateTransaction(pb);
  1929.     }
  1930.     else
  1931.     {
  1932.         USBExpertFatalError(pPrinterPB->device, pPrinterPB->pb.usbStatus, StateStr(pPrinterPB->pb.usbRefcon, kPString), pPrinterPB->pb.usbRefcon);
  1933.         USBExpertFatalError(pPrinterPB->device, pPrinterPB->pb.usbStatus, USBStatusStr(pPrinterPB->pb.usbStatus, kPString), 0);
  1934.     }
  1935. }
  1936.  
  1937. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1938.     Name:        PrinterDeviceInitiateTransaction
  1939.  
  1940.     Input Parameters:    
  1941.         pb            USB parameter block
  1942.         
  1943.     Output Parameters:
  1944.         
  1945.     Description:
  1946.         Since USB transactions are asynchronous we use the refCon field
  1947.         in the parameter block to implement the following logic via a state machine.
  1948.  
  1949.         Start out by getting the device configuration descriptor
  1950.         If the device has more than one printing interface
  1951.             If a bidirectional interface exists
  1952.                 select it
  1953.             Else
  1954.                 select the (mandatory) unidirectional interface
  1955.         Get the (manadatory) 1284 capability string
  1956.         Open pipes to the BulkOut (and optional BulkIn) endpoints
  1957.         Install read and write drivers in the unit table
  1958.         Using information from the capability string
  1959.             enter the printer in the MacOS name registry.
  1960.         
  1961.  
  1962.     Change History:
  1963.         15 May 1998,    oja:        cleanup error/status messages
  1964.                                         handle setinterface correctly if only one
  1965.                                             interface is available
  1966.         28 Feb 1998,    oja:        Original version.
  1967. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1968. void
  1969. PrinterDeviceInitiateTransaction(USBPB *pb)
  1970. {
  1971.     register struct usbPrinterPBStruct    *pPrinterPB;
  1972.     int                                            length;
  1973.     OSStatus                                        err;
  1974.  
  1975.     pPrinterPB = (struct usbPrinterPBStruct *)(pb);
  1976.     pPrinterPB->transDepth++;
  1977.     if ((pPrinterPB->transDepth < 0) || (pPrinterPB->transDepth > 1))
  1978.     {
  1979.         USBExpertFatalError(pPrinterPB->device, kUSBInternalErr, "\p" kStrPrinterClass "InitiateTransaction illegal transaction depth", 0);
  1980.     }
  1981.     IF_DEBUG( USBExpertStatus( pPrinterPB->device, StateStr(pPrinterPB->pb.usbRefcon, kPString), 0) );     
  1982.  
  1983.     switch(pPrinterPB->pb.usbRefcon & ~kRetryTransaction)
  1984.     {
  1985.         case kGetConfigurationDescriptor:
  1986.             //
  1987.             //    find the device's configuration information
  1988.             //
  1989.             pPrinterPB->config = (USBConfigurationDescriptorPtr) pPrinterPB->configuration;
  1990.             GetConfigurationDescriptor( &pPrinterPB->pb, pPrinterPB->config, sizeof(USBConfigurationDescriptor) );
  1991.             break;
  1992.             
  1993.         case kGetFullConfiguration:
  1994.             //
  1995.             //    not enough room in statically allocated memory for device's configuration
  1996.             //    try again after allocating enough memory
  1997.             //        (memory is released on finalize)
  1998.             length = USBToHostWord( (pPrinterPB->config)->totalLength );
  1999.  
  2000.             pPrinterPB->config = MemAllocatePhysicallyContiguous ((ByteCount)length, true);
  2001.             GetConfigurationDescriptor( &pPrinterPB->pb, pPrinterPB->config, length );
  2002.             break;
  2003.         case kSetInterface:
  2004.             //
  2005.             //    having identified the configuration
  2006.             //        set the device to our prefered interface
  2007.             //
  2008.             SetInterface( &pPrinterPB->pb, pPrinterPB->interface->interfaceNumber, pPrinterPB->interface->alternateSetting );
  2009.             break;
  2010.         case kGetCapabilityString:
  2011.             //
  2012.             //    once the interface (and alternate) is assinged
  2013.             //        we can retreive the 1284 capability string to see what kind of printer
  2014.             //        is attached
  2015.             pPrinterPB->capabilityString = pPrinterPB->capability;
  2016.             GetCapability( pPrinterPB, pPrinterPB->capabilityString, sizeof(pPrinterPB->capability) );
  2017.             break;
  2018.         case kDelayGetCapability:
  2019.             //
  2020.             //    USS-720 USB-parallel cable: couldn't get the capability string because the printer is off
  2021.             //        Delay a few seconds and try again.
  2022.             //        Will succeed when the user turns the printer on.
  2023.             //
  2024.             pPrinterPB->pb.usbReqCount = kUSS720MillisecondDelay;
  2025.             pPrinterPB->pb.usbRefcon |= kTransactionPending | kAsyncTransaction;
  2026.             err = USBDelay(&pPrinterPB->pb);
  2027.             if(immediateError(err))
  2028.             {
  2029.                 USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "kDelayGetCapability", 0);
  2030.             }
  2031.             break;
  2032.         case kGetFullCapabilityString:
  2033.             //
  2034.             // the capability string was too long to fit in the statically allocated space
  2035.             // need to release this memory when we finalize our driver
  2036.             //
  2037.             length = pPrinterPB->capability[1] | (pPrinterPB->capability[0]<<8);
  2038.  
  2039.             pPrinterPB->capabilityString = MemAllocatePhysicallyContiguous ((ByteCount)length, true);
  2040.             if ( pPrinterPB->capabilityString )
  2041.                 GetCapability( pPrinterPB, pPrinterPB->capabilityString, length );
  2042.             else
  2043.                 USBExpertFatalError(pPrinterPB->device, kUSBInternalErr, "\p" kStrPrinterClass "Can't allocate capability", 0);
  2044.             break;
  2045.         case kGetInterface:
  2046.             // failsafe check that we've got the right setup
  2047.             //    it's possible the device didn't respond to our SetInterface
  2048.             GetInterface( &pPrinterPB->pb, &pPrinterPB->whichAltInterface );
  2049.             break;
  2050.         case kOpenBulkOutPipe:
  2051.             //
  2052.             //    open mandatory bulk out pipe
  2053.             //
  2054.             OpenBulkEndpoint( pPrinterPB, kOpenBulkOutPipe );
  2055.             break;
  2056.         case kOpenBulkInPipe:    
  2057.             //
  2058.             //    open optional bulk in pipe
  2059.             //
  2060.             OpenBulkEndpoint( pPrinterPB, kOpenBulkInPipe );
  2061.             break;
  2062.         case kEnterNameRegistry:
  2063.             //
  2064.             //    once we know what device we're dealing with
  2065.             //        open the i/o channel(s) to the device
  2066.             //        and enter it in the name registry
  2067.             //
  2068.             err = InstallDrivers( pPrinterPB );
  2069.             if ( err == noErr )
  2070.                 err = RegisterDevice( pPrinterPB );
  2071.             if ( err != noErr )
  2072.                 USBExpertFatalError(pPrinterPB->device, err, "\p" kStrPrinterClass "RegisterDevice failed", 0);
  2073.             //
  2074.             //    that's it
  2075.             //        all other transactions proceed through QueueWrite and QueueRead
  2076.             //        from the drivers we've installed in the unit table
  2077.             //
  2078.             pPrinterPB->pb.usbRefcon = kUndefined + kReturnFromDriver;    // nothing else to do until we have i/o
  2079.             break;
  2080.         case kReturnFromDriver:
  2081.             break;
  2082.         default:
  2083.             USBExpertFatalError(pPrinterPB->device, kUSBInternalErr, "\p" kStrPrinterClass "InitiateTransaction unknown transaction", 0);
  2084.             pPrinterPB->pb.usbRefcon = kUndefined + kReturnFromDriver;
  2085.             break;
  2086.     }
  2087. }
  2088.  
  2089.  
  2090. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2091.     Name:        PrintDriverEntry
  2092.  
  2093.     Input Parameters:    
  2094.         
  2095.     Output Parameters:
  2096.         
  2097.     Description:
  2098.         This is where the system instantiates a USB printing device.
  2099.  
  2100.         We need to install drivers in the MacOS unitTable, and a reference
  2101.         in the name registry.
  2102.         
  2103.         But the information we need to do this is only available after some 
  2104.         USB transactions have completed. So we initiate here a series of asynchronous
  2105.         USB operations to get that information (by calling the first 
  2106.  
  2107.     Change History:
  2108.         30 Jun 1998,    oja:        change CentronicsStatus to ControlStatusRequests
  2109.         28 Feb 1998,    oja:        Original version.
  2110. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2111. void 
  2112. PrintDriverEntry(
  2113.     USBDeviceRef                    device,
  2114.     USBDeviceDescriptorPtr        desc,
  2115.     USBInterfaceDescriptorPtr    pInterface
  2116.     )
  2117. {
  2118.     static Boolean        beenThereDoneThat = false;
  2119.     OSStatus                err;
  2120.     RoutineDescriptor qw = BUILD_ROUTINE_DESCRIPTOR( uppQueueUSBWriteProcInfo, QueueWrite);
  2121.     RoutineDescriptor qr = BUILD_ROUTINE_DESCRIPTOR( uppQueueUSBReadProcInfo, QueueRead);
  2122.     RoutineDescriptor qa = BUILD_ROUTINE_DESCRIPTOR( uppAbortProcInfo, Abort);
  2123.     RoutineDescriptor qs = BUILD_ROUTINE_DESCRIPTOR( uppControlStatusProcInfo, ControlStatusRequests );
  2124.     
  2125.     if( !beenThereDoneThat)
  2126.     {
  2127.         beenThereDoneThat = true;
  2128.             
  2129.         printerClassRecord.desc = *desc;                /* keep a copy of the device descriptor */
  2130.         if ( pInterface != NULL )
  2131.             printerClassRecord.interface = pInterface;
  2132.     
  2133.         printerClassRecord.device = device;
  2134.         printerClassRecord.transDepth = 0;            /* init Delay Callback Depth */
  2135.  
  2136.         printerClassRecord.terminating = 0;
  2137.         printerClassRecord.out.usbCompletion = NULL;
  2138.         printerClassRecord.in.usbCompletion = NULL;
  2139.     
  2140.         printerClassRecord.inRefNum =  -1;            /* initially no DRVRs added to UnitTable */
  2141.         printerClassRecord.outRefNum =  -1;    
  2142.         err = LoadResources( &printerClassRecord );
  2143.         if ( err != noErr )
  2144.             USBExpertFatalError( device, err, "\p" kStrPrinterClass "LoadResources failed", 0);
  2145.         //
  2146.         //    routines to write and read to the device must be called by 68K DRVR
  2147.         //        so we use mixed-mode manager to dispatch between PPC and 68K
  2148.         //
  2149.         printerClassRecord.qwrite = (QueueUSBWriteUPP) &printerClassRecord.qwriteRD;
  2150.         printerClassRecord.qwriteRD = qw;
  2151.     
  2152.         printerClassRecord.qread = (QueueUSBReadUPP) &printerClassRecord.qreadRD;
  2153.         printerClassRecord.qreadRD = qr;    
  2154.         
  2155.         printerClassRecord.qstatus = (ControlStatusUPP) &printerClassRecord.qstatusRD;
  2156.         printerClassRecord.qstatusRD = qs;
  2157.  
  2158.         printerClassRecord.qabort = (AbortUPP) &printerClassRecord.qabortRD;
  2159.         printerClassRecord.qabortRD = qa;
  2160.  
  2161.         printerClassRecord.r = (QueueUSBReadUPP) QueueRead;
  2162.         printerClassRecord.w = (QueueUSBWriteUPP) QueueWrite;
  2163.         printerClassRecord.s = (ControlStatusUPP) ControlStatusRequests;
  2164.         printerClassRecord.a = (AbortUPP) Abort;
  2165.  
  2166.         SetNullUSBParamBlock( device, &printerClassRecord.pb );
  2167.         SetNullUSBParamBlock( 0, &printerClassRecord.in );        // fill in pipe ref later
  2168.         SetNullUSBParamBlock( 0, &printerClassRecord.out );    // fill in pipe ref later
  2169.  
  2170.          /* Start out at first state */
  2171.         printerClassRecord.pb.usbRefcon = kGetConfigurationDescriptor;
  2172.         PrinterDeviceInitiateTransaction(&printerClassRecord.pb);
  2173.     }
  2174. }
  2175.  
  2176. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2177.     Name:        PrintDriverFinalize
  2178.  
  2179.     Input Parameters:    
  2180.         
  2181.     Output Parameters:
  2182.         
  2183.     Description:
  2184.         release any allocated storage
  2185.         remove DRVRs from the UnitTable
  2186.  
  2187.         One small complication happens when the USS-720 cable is used. It's possible
  2188.         that the user has the device plugged in, but the printer wasn't powered on.
  2189.         In this case, our state machine is still cycling between the states 
  2190.         kDelayGetCapability and kGetCapabilityString. If we terminate before the delay
  2191.         returns we'll crash the system. We monitor terminating to handle this
  2192.         
  2193.     Change History:
  2194.         12 Jul 1998,    oja:        allow for hot unplugging during initial startup
  2195.                                             wait for completion if refCon indicates some
  2196.                                             transaction is in progress
  2197.         24 Apr 1998,    oja:        added call to DeregisterDevice
  2198.         28 Feb 1998,    oja:        Original version.
  2199. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2200. OSStatus
  2201. PrintDriverFinalize( void )
  2202. {
  2203.     UInt32    refCon =    printerClassRecord.pb.usbRefcon & ~(kTransactionPending + kAsyncTransaction);
  2204.     OSStatus    result = noErr;
  2205.     //
  2206.     //    notify state machine not to continue
  2207.     //
  2208.     printerClassRecord.terminating = 1;
  2209.     //
  2210.     //    abort and wait for any pending read/write/status calls
  2211.     //
  2212.     if ( printerClassRecord.in.usbCompletion != NULL )
  2213.     {
  2214.         USBAbortPipeByReference( printerClassRecord.readPipe );
  2215.     }
  2216.     if ( printerClassRecord.out.usbCompletion != NULL )
  2217.     {
  2218.         USBAbortPipeByReference( printerClassRecord.writePipe );
  2219.     }
  2220.     //    wait for any outstanding startup transactions
  2221.     if ( refCon != kReturnFromDriver
  2222.             || printerClassRecord.out.usbCompletion != NULL 
  2223.             || printerClassRecord.in.usbCompletion != NULL )
  2224.         result = (OSStatus) kUSBDeviceBusy;
  2225.     else
  2226.     {
  2227.         //
  2228.         //    release any allocated storage
  2229.         //
  2230.         if ( printerClassRecord.capabilityString != printerClassRecord.capability )
  2231.             MemDeallocatePhysicallyContiguous( printerClassRecord.capabilityString );
  2232.     
  2233.         if ( (unsigned char *) printerClassRecord.config != printerClassRecord.configuration )
  2234.             MemDeallocatePhysicallyContiguous( printerClassRecord.config );
  2235.         //
  2236.         //    remove printer from the name registry
  2237.         //
  2238.         DeregisterDevice( &printerClassRecord );
  2239.     }
  2240.     
  2241.     return result;
  2242. }
  2243.  
  2244. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2245.     Name:        CFMInitialization
  2246.  
  2247.     Input Parameters:    
  2248.         initBlock
  2249.         
  2250.     Output Parameters:
  2251.         printerClassDriverFileSpec        set global
  2252.         
  2253.     Description:
  2254.         we use the code fragment initialization to get our filespec 
  2255.         LoadResources will use to open our resource fork
  2256.  
  2257.     Change History:
  2258.         11 Jun 1998,    oja:        Original version.
  2259. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2260. OSErr
  2261. CFMInitialization( CFragInitBlock *initBlock )
  2262. {
  2263.     //
  2264.     //    get a reference to our file so that we can open up the resource fork later on
  2265.     //
  2266.     if ( CFragHasFileLocation( initBlock->fragLocator.where ) )
  2267.         printerClassDriverFileSpec = *(initBlock->fragLocator.u.onDisk.fileSpec);
  2268.  
  2269.     return noErr;
  2270. }
  2271.  
  2272. // eof
  2273.